/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package biofilter.filters;


import biofilter.exceptions.InvalidRecordException;
import biofilter.sources.RecordsSourceIF;
import biofilter.records.Record;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.LinkedList;
/**
 *
 * @author Daniel Quest
 * @date   Jan 4th 2010
 */
public class CompositeFilter extends RecordsFilter {
    LinkedList<Object> filters;
    protected Logger logger = null;

    /** Creates a new instance of CompositeFilter */
    public CompositeFilter() {
        super();
        this.logger = Logger.getLogger(this.getClass().getName());
        filters = new LinkedList<Object>();
    }

    /**
     * Set the composite filter source.
     * @param Object RecordsFile the source of the composite filter
     */
    @Override
    public void setSource( Object source ) throws IllegalArgumentException {
        logger.log(Level.INFO, "composite filter set source");
        logger.log(Level.INFO , "setting source to:  " + source);
        super.setSource(  source );
        logger.log(Level.INFO, "filters:  " + filters);
        if ( !filters.isEmpty()) {
            RecordsFilter filter = (RecordsFilter) filters.getFirst();
            logger.log( Level.INFO,  "setting first filter: " + filter.getClass().getName() + " soucre to " + source);
            filter.setSource( source);
        }
    }
    /**
     * for debugging....
     */
     public Object getSource(){
         return this.source;
     }

    /**
     * To get a record from the pipeline.  This is sort of different from normal filters,
     * because here the transformation has already happened.  However, transform record is
     * called to allow this filter to additionally transform the result.
     * @return Record - the result of calling getRecord on the last filter
     */
    public Record getRecord() throws InvalidRecordException{

        if( filters.isEmpty() ){  //here we have a source an no filter so just return the source!
            return this.source.getRecord();
        }
        RecordsFilter filter = (RecordsFilter) filters.getLast();

        originalRecord = filter.getRecord();

        if ( originalRecord == null) {
            return null;
        }

        transformedRecord = this.transformRecord(originalRecord);

        return transformedRecord;
    }

    public Record peek() throws InvalidRecordException {
        RecordsFilter filter = (RecordsFilter) filters.getLast();
        return (Record) filter.peek();
    }

    /**
     * provide a hook for additional transformation logic
     * Default implemenation just returns the originalRecord -
     * can be overridden in a descendant class if necessary.
     * @param Record r the record to be transformed
     * @return Record - the same record
     */
    protected Record transformRecord( Record r ) throws InvalidRecordException {
        return r;
    }

    /**
     * Pipeline is done when the last filter in the pipeline is at eof().
     * @return boolean - true if the composite filter is done, false if it is not
     */
    public boolean eof() {
        RecordsFilter filter = (RecordsFilter) filters.getLast();

        if ( filter == null)
            return true;
        else
            return filter.eof();
    }

    /**
     * Add a filter to the list of filters.
     * @param RecordsFilter the RecordsFilter to be added to the composite filter
     */
    public void addFilter( RecordsFilter filter ) {
        logger.log(Level.INFO, "adding filter... " + filter.getClass().getName());
        try {
            logger.log(Level.INFO,  "setting filter source " );
        if ( filters.isEmpty())
            filter.setSource( this.source );
        else
            filter.setSource( filters.getLast() );
        }catch( IllegalArgumentException ire ) {
            logger.log(Level.SEVERE,   "InvalidRecordException in addFilter of CompositeFilter: " + ire.toString() );
        }

        filters.add( filter);
    }
}
